home *** CD-ROM | disk | FTP | other *** search
- Subject: v16i031: Less, a pager that's more than more, Part02/04
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: ctnews!UNIX386!mark
- Posting-number: Volume 16, Issue 31
- Archive-name: less5/part02
-
- #! /bin/sh
- # This is a shell archive.
- # Remove anything before this line, then unpack it
- # by saving it into a file and typing "sh file".
-
- echo shar: Extracting \"screen.c\"
- sed "s/^X//" >'screen.c' <<'END_OF_FILE'
- X/*
- X * Routines which deal with the characteristics of the terminal.
- X * Uses termcap to be as terminal-independent as possible.
- X *
- X * {{ Someday this should be rewritten to use curses. }}
- X */
- X
- X#include "less.h"
- X#if XENIX
- X#include <sys/types.h>
- X#include <sys/ioctl.h>
- X#endif
- X
- X#if TERMIO
- X#include <termio.h>
- X#else
- X#include <sgtty.h>
- X#endif
- X
- X#ifdef TIOCGWINSZ
- X#include <sys/ioctl.h>
- X#else
- X/*
- X * For the Unix PC (ATT 7300 & 3B1):
- X * Since WIOCGETD is defined in sys/window.h, we can't use that to decide
- X * whether to include sys/window.h. Use SIGPHONE from sys/signal.h instead.
- X */
- X#include <sys/signal.h>
- X#ifdef SIGPHONE
- X#include <sys/window.h>
- X#endif
- X#endif
- X
- X/*
- X * Strings passed to tputs() to do various terminal functions.
- X */
- Xstatic char
- X *sc_pad, /* Pad string */
- X *sc_home, /* Cursor home */
- X *sc_addline, /* Add line, scroll down following lines */
- X *sc_lower_left, /* Cursor to last line, first column */
- X *sc_move, /* General cursor positioning */
- X *sc_clear, /* Clear screen */
- X *sc_eol_clear, /* Clear to end of line */
- X *sc_s_in, /* Enter standout (highlighted) mode */
- X *sc_s_out, /* Exit standout mode */
- X *sc_u_in, /* Enter underline mode */
- X *sc_u_out, /* Exit underline mode */
- X *sc_b_in, /* Enter bold mode */
- X *sc_b_out, /* Exit bold mode */
- X *sc_visual_bell, /* Visual bell (flash screen) sequence */
- X *sc_backspace, /* Backspace cursor */
- X *sc_init, /* Startup terminal initialization */
- X *sc_deinit; /* Exit terminal de-intialization */
- X
- Xpublic int auto_wrap; /* Terminal does \r\n when write past margin */
- Xpublic int ignaw; /* Terminal ignores \n immediately after wrap */
- Xpublic int erase_char, kill_char; /* The user's erase and line-kill chars */
- Xpublic int sc_width, sc_height; /* Height & width of screen */
- Xpublic int sc_window = -1; /* window size for forward and backward */
- Xpublic int bo_width, be_width; /* Printing width of boldface sequences */
- Xpublic int ul_width, ue_width; /* Printing width of underline sequences */
- Xpublic int so_width, se_width; /* Printing width of standout sequences */
- X
- X/*
- X * These two variables are sometimes defined in,
- X * and needed by, the termcap library.
- X * It may be necessary on some systems to declare them extern here.
- X */
- X/*extern*/ short ospeed; /* Terminal output baud rate */
- X/*extern*/ char PC; /* Pad character */
- X
- Xextern int quiet; /* If VERY_QUIET, use visual bell for bell */
- Xextern int know_dumb; /* Don't complain about a dumb terminal */
- Xextern int back_scroll;
- Xchar *tgetstr();
- Xchar *tgoto();
- X
- X/*
- X * Change terminal to "raw mode", or restore to "normal" mode.
- X * "Raw mode" means
- X * 1. An outstanding read will complete on receipt of a single keystroke.
- X * 2. Input is not echoed.
- X * 3. On output, \n is mapped to \r\n.
- X * 4. \t is NOT expanded into spaces.
- X * 5. Signal-causing characters such as ctrl-C (interrupt),
- X * etc. are NOT disabled.
- X * It doesn't matter whether an input \n is mapped to \r, or vice versa.
- X */
- X public void
- Xraw_mode(on)
- X int on;
- X{
- X#if TERMIO
- X struct termio s;
- X static struct termio save_term;
- X
- X if (on)
- X {
- X /*
- X * Get terminal modes.
- X */
- X ioctl(2, TCGETA, &s);
- X
- X /*
- X * Save modes and set certain variables dependent on modes.
- X */
- X save_term = s;
- X ospeed = s.c_cflag & CBAUD;
- X erase_char = s.c_cc[VERASE];
- X kill_char = s.c_cc[VKILL];
- X
- X /*
- X * Set the modes to the way we want them.
- X */
- X s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
- X s.c_oflag |= (OPOST|ONLCR|TAB3);
- X s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
- X s.c_cc[VMIN] = 1;
- X s.c_cc[VTIME] = 0;
- X } else
- X {
- X /*
- X * Restore saved modes.
- X */
- X s = save_term;
- X }
- X ioctl(2, TCSETAW, &s);
- X#else
- X struct sgttyb s;
- X static struct sgttyb save_term;
- X
- X if (on)
- X {
- X /*
- X * Get terminal modes.
- X */
- X ioctl(2, TIOCGETP, &s);
- X
- X /*
- X * Save modes and set certain variables dependent on modes.
- X */
- X save_term = s;
- X ospeed = s.sg_ospeed;
- X erase_char = s.sg_erase;
- X kill_char = s.sg_kill;
- X
- X /*
- X * Set the modes to the way we want them.
- X */
- X s.sg_flags |= CBREAK;
- X s.sg_flags &= ~(ECHO|XTABS);
- X } else
- X {
- X /*
- X * Restore saved modes.
- X */
- X s = save_term;
- X }
- X ioctl(2, TIOCSETN, &s);
- X#endif
- X}
- X
- X static void
- Xcannot(s)
- X char *s;
- X{
- X char message[100];
- X
- X if (know_dumb)
- X /*
- X * He knows he has a dumb terminal, so don't tell him.
- X */
- X return;
- X
- X sprintf(message, "WARNING: terminal cannot \"%s\"", s);
- X error(message);
- X}
- X
- X/*
- X * Get terminal capabilities via termcap.
- X */
- X public void
- Xget_term()
- X{
- X char termbuf[2048];
- X char *sp;
- X char *term;
- X int hard;
- X#ifdef TIOCGWINSZ
- X struct winsize w;
- X#else
- X#ifdef WIOCGETD
- X struct uwdata w;
- X#endif
- X#endif
- X static char sbuf[1024];
- X
- X char *getenv();
- X
- X /*
- X * Find out what kind of terminal this is.
- X */
- X if ((term = getenv("TERM")) == NULL)
- X term = "unknown";
- X if (tgetent(termbuf, term) <= 0)
- X strcpy(termbuf, "dumb:co#80:hc:");
- X
- X /*
- X * Get size of the screen.
- X */
- X#ifdef TIOCGWINSZ
- X if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_row > 0)
- X sc_height = w.ws_row;
- X else
- X#else
- X#ifdef WIOCGETD
- X if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_height > 0)
- X sc_height = w.uw_height/w.uw_vs;
- X else
- X#endif
- X#endif
- X sc_height = tgetnum("li");
- X hard = (sc_height < 0 || tgetflag("hc"));
- X if (hard)
- X {
- X /* Oh no, this is a hardcopy terminal. */
- X sc_height = 24;
- X }
- X
- X#ifdef TIOCGWINSZ
- X if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)
- X sc_width = w.ws_col;
- X else
- X#ifdef WIOCGETD
- X if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_width > 0)
- X sc_width = w.uw_width/w.uw_hs;
- X else
- X#endif
- X#endif
- X sc_width = tgetnum("co");
- X if (sc_width < 0)
- X sc_width = 80;
- X
- X auto_wrap = tgetflag("am");
- X ignaw = tgetflag("xn");
- X
- X /*
- X * Assumes termcap variable "sg" is the printing width of
- X * the standout sequence, the end standout sequence,
- X * the underline sequence, the end underline sequence,
- X * the boldface sequence, and the end boldface sequence.
- X */
- X if ((so_width = tgetnum("sg")) < 0)
- X so_width = 0;
- X be_width = bo_width = ue_width = ul_width = se_width = so_width;
- X
- X /*
- X * Get various string-valued capabilities.
- X */
- X sp = sbuf;
- X
- X sc_pad = tgetstr("pc", &sp);
- X if (sc_pad != NULL)
- X PC = *sc_pad;
- X
- X sc_init = tgetstr("ti", &sp);
- X if (sc_init == NULL)
- X sc_init = "";
- X
- X sc_deinit= tgetstr("te", &sp);
- X if (sc_deinit == NULL)
- X sc_deinit = "";
- X
- X sc_eol_clear = tgetstr("ce", &sp);
- X if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
- X {
- X cannot("clear to end of line");
- X sc_eol_clear = "";
- X }
- X
- X sc_clear = tgetstr("cl", &sp);
- X if (hard || sc_clear == NULL || *sc_clear == '\0')
- X {
- X cannot("clear screen");
- X sc_clear = "\n\n";
- X }
- X
- X sc_move = tgetstr("cm", &sp);
- X if (hard || sc_move == NULL || *sc_move == '\0')
- X {
- X /*
- X * This is not an error here, because we don't
- X * always need sc_move.
- X * We need it only if we don't have home or lower-left.
- X */
- X sc_move = "";
- X }
- X
- X sc_s_in = tgetstr("so", &sp);
- X if (hard || sc_s_in == NULL)
- X sc_s_in = "";
- X
- X sc_s_out = tgetstr("se", &sp);
- X if (hard || sc_s_out == NULL)
- X sc_s_out = "";
- X
- X sc_u_in = tgetstr("us", &sp);
- X if (hard || sc_u_in == NULL)
- X sc_u_in = sc_s_in;
- X
- X sc_u_out = tgetstr("ue", &sp);
- X if (hard || sc_u_out == NULL)
- X sc_u_out = sc_s_out;
- X
- X sc_b_in = tgetstr("md", &sp);
- X if (hard || sc_b_in == NULL)
- X {
- X sc_b_in = sc_s_in;
- X sc_b_out = sc_s_out;
- X } else
- X {
- X sc_b_out = tgetstr("me", &sp);
- X if (hard || sc_b_out == NULL)
- X sc_b_out = "";
- X }
- X
- X sc_visual_bell = tgetstr("vb", &sp);
- X if (hard || sc_visual_bell == NULL)
- X sc_visual_bell = "";
- X
- X sc_home = tgetstr("ho", &sp);
- X if (hard || sc_home == NULL || *sc_home == '\0')
- X {
- X if (*sc_move == '\0')
- X {
- X cannot("home cursor");
- X /*
- X * This last resort for sc_home is supposed to
- X * be an up-arrow suggesting moving to the
- X * top of the "virtual screen". (The one in
- X * your imagination as you try to use this on
- X * a hard copy terminal.)
- X */
- X sc_home = "|\b^";
- X } else
- X {
- X /*
- X * No "home" string,
- X * but we can use "move(0,0)".
- X */
- X strcpy(sp, tgoto(sc_move, 0, 0));
- X sc_home = sp;
- X sp += strlen(sp) + 1;
- X }
- X }
- X
- X sc_lower_left = tgetstr("ll", &sp);
- X if (hard || sc_lower_left == NULL || *sc_lower_left == '\0')
- X {
- X if (*sc_move == '\0')
- X {
- X cannot("move cursor to lower left of screen");
- X sc_lower_left = "\r";
- X } else
- X {
- X /*
- X * No "lower-left" string,
- X * but we can use "move(0,last-line)".
- X */
- X strcpy(sp, tgoto(sc_move, 0, sc_height-1));
- X sc_lower_left = sp;
- X sp += strlen(sp) + 1;
- X }
- X }
- X
- X /*
- X * To add a line at top of screen and scroll the display down,
- X * we use "al" (add line) or "sr" (scroll reverse).
- X */
- X if ((sc_addline = tgetstr("al", &sp)) == NULL ||
- X *sc_addline == '\0')
- X sc_addline = tgetstr("sr", &sp);
- X
- X if (hard || sc_addline == NULL || *sc_addline == '\0')
- X {
- X cannot("scroll backwards");
- X sc_addline = "";
- X /* Force repaint on any backward movement */
- X back_scroll = 0;
- X }
- X
- X if (tgetflag("bs"))
- X sc_backspace = "\b";
- X else
- X {
- X sc_backspace = tgetstr("bc", &sp);
- X if (sc_backspace == NULL || *sc_backspace == '\0')
- X sc_backspace = "\b";
- X }
- X}
- X
- X
- X/*
- X * Below are the functions which perform all the
- X * terminal-specific screen manipulation.
- X */
- X
- X
- X/*
- X * Initialize terminal
- X */
- X public void
- Xinit()
- X{
- X tputs(sc_init, sc_height, putchr);
- X}
- X
- X/*
- X * Deinitialize terminal
- X */
- X public void
- Xdeinit()
- X{
- X tputs(sc_deinit, sc_height, putchr);
- X}
- X
- X/*
- X * Home cursor (move to upper left corner of screen).
- X */
- X public void
- Xhome()
- X{
- X tputs(sc_home, 1, putchr);
- X}
- X
- X/*
- X * Add a blank line (called with cursor at home).
- X * Should scroll the display down.
- X */
- X public void
- Xadd_line()
- X{
- X tputs(sc_addline, sc_height, putchr);
- X}
- X
- X/*
- X * Move cursor to lower left corner of screen.
- X */
- X public void
- Xlower_left()
- X{
- X tputs(sc_lower_left, 1, putchr);
- X}
- X
- X/*
- X * Ring the terminal bell.
- X */
- X public void
- Xbell()
- X{
- X if (quiet == VERY_QUIET)
- X vbell();
- X else
- X putchr('\7');
- X}
- X
- X/*
- X * Output the "visual bell", if there is one.
- X */
- X public void
- Xvbell()
- X{
- X if (*sc_visual_bell == '\0')
- X return;
- X tputs(sc_visual_bell, sc_height, putchr);
- X}
- X
- X/*
- X * Clear the screen.
- X */
- X public void
- Xclear()
- X{
- X tputs(sc_clear, sc_height, putchr);
- X}
- X
- X/*
- X * Clear from the cursor to the end of the cursor's line.
- X * {{ This must not move the cursor. }}
- X */
- X public void
- Xclear_eol()
- X{
- X tputs(sc_eol_clear, 1, putchr);
- X}
- X
- X/*
- X * Begin "standout" (bold, underline, or whatever).
- X */
- X public void
- Xso_enter()
- X{
- X tputs(sc_s_in, 1, putchr);
- X}
- X
- X/*
- X * End "standout".
- X */
- X public void
- Xso_exit()
- X{
- X tputs(sc_s_out, 1, putchr);
- X}
- X
- X/*
- X * Begin "underline" (hopefully real underlining,
- X * otherwise whatever the terminal provides).
- X */
- X public void
- Xul_enter()
- X{
- X tputs(sc_u_in, 1, putchr);
- X}
- X
- X/*
- X * End "underline".
- X */
- X public void
- Xul_exit()
- X{
- X tputs(sc_u_out, 1, putchr);
- X}
- X
- X/*
- X * Begin "bold"
- X */
- X public void
- Xbo_enter()
- X{
- X tputs(sc_b_in, 1, putchr);
- X}
- X
- X/*
- X * End "bold".
- X */
- X public void
- Xbo_exit()
- X{
- X tputs(sc_b_out, 1, putchr);
- X}
- X
- X/*
- X * Erase the character to the left of the cursor
- X * and move the cursor left.
- X */
- X public void
- Xbackspace()
- X{
- X /*
- X * Try to erase the previous character by overstriking with a space.
- X */
- X tputs(sc_backspace, 1, putchr);
- X putchr(' ');
- X tputs(sc_backspace, 1, putchr);
- X}
- X
- X/*
- X * Output a plain backspace, without erasing the previous char.
- X */
- X public void
- Xputbs()
- X{
- X tputs(sc_backspace, 1, putchr);
- X}
- END_OF_FILE
- echo shar: Extracting \"prompt.c\"
- sed "s/^X//" >'prompt.c' <<'END_OF_FILE'
- X/*
- X * Prompting and other messages.
- X * There are three flavors of prompts, SHORT, MEDIUM and LONG,
- X * selected by the -m/-M options.
- X * There is also the "equals message", printed by the = command.
- X * A prompt is a message composed of various pieces, such as the
- X * name of the file being viewed, the percentage into the file, etc.
- X */
- X
- X#include "less.h"
- X#include "position.h"
- X
- Xextern int pr_type;
- Xextern int ispipe;
- Xextern int hit_eof;
- Xextern int new_file;
- Xextern int sc_width;
- Xextern int so_width, se_width;
- Xextern char *current_file;
- Xextern int ac;
- Xextern char **av;
- Xextern int curr_ac;
- Xextern int linenums;
- X
- X/*
- X * Prototypes for the three flavors of prompts.
- X * These strings are expanded by pr_expand().
- X */
- Xstatic char s_proto[] =
- X "?n?f%f .?m(file %i of %m) ..?e(END) ?x- Next\\: %x..%t";
- Xstatic char m_proto[] =
- X "?n?f%f .?m(file %i of %m) ..?e(END) ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t";
- Xstatic char M_proto[] =
- X "?f%f .?n?m(file %i of %m) ..?ltline %lt :byte %bB?s/%s ..?e(END) ?x- Next\\: %x.:?pB%pB\\%..%t";
- Xstatic char e_proto[] =
- X "?f%f .?m(file %i of %m) .?ltline %lt .byte %bB?s/%s. ?e(END) :?pB%pB\\%..%t";
- X
- Xchar *prproto[3];
- Xchar *eqproto = e_proto;
- X
- Xstatic char message[250];
- Xstatic char *mp;
- X
- X/*
- X * Initialize the prompt prototype strings.
- X */
- X public void
- Xinit_prompt()
- X{
- X prproto[0] = save(s_proto);
- X prproto[1] = save(m_proto);
- X prproto[2] = save(M_proto);
- X eqproto = save(e_proto);
- X}
- X
- X/*
- X * Set the message pointer to the end of the message string.
- X */
- X static void
- Xsetmp()
- X{
- X while (*mp != '\0')
- X mp++;
- X}
- X
- X/*
- X * Append a POSITION (as a decimal integer) to the end of the message.
- X */
- X static void
- Xap_pos(pos)
- X POSITION pos;
- X{
- X sprintf(mp, "%ld", (long)pos);
- X setmp();
- X}
- X
- X/*
- X * Append an integer to the end of the message.
- X */
- X static void
- Xap_int(n)
- X int n;
- X{
- X sprintf(mp, "%d", n);
- X setmp();
- X}
- X
- X/*
- X * Append a question mark to the end of the message.
- X */
- X static void
- Xap_quest()
- X{
- X *mp++ = '?';
- X}
- X
- X/*
- X * Return the "current" byte offset in the file.
- X */
- X static POSITION
- Xcurr_byte(where)
- X int where;
- X{
- X POSITION pos;
- X
- X pos = position(where);
- X if (pos == NULL_POSITION)
- X pos = ch_length();
- X return (pos);
- X}
- X
- X/*
- X * Return the value of a prototype conditional.
- X * A prototype string may include conditionals which consist of a
- X * question mark followed by a single letter.
- X * Here we decode that letter and return the appropriate boolean value.
- X */
- X static int
- Xcond(c, where)
- X char c;
- X int where;
- X{
- X switch (c)
- X {
- X case 'a': /* Anything in the message yet? */
- X return (mp > message);
- X case 'b': /* Current byte offset known? */
- X return (curr_byte(where) != NULL_POSITION);
- X case 'e': /* At end of file? */
- X return (hit_eof);
- X case 'f': /* Filename known? */
- X return (!ispipe);
- X case 'l': /* Line number known? */
- X return (linenums);
- X case 'm': /* More than one file? */
- X return (ac > 1);
- X case 'n': /* First prompt in a new file? */
- X return (new_file);
- X case 'p': /* Percent into file known? */
- X return (curr_byte(where) != NULL_POSITION &&
- X ch_length() > 0);
- X case 's': /* Size of file known? */
- X return (ch_length() != NULL_POSITION);
- X case 'x': /* Is there a "next" file? */
- X return (curr_ac + 1 < ac);
- X }
- X return (0);
- X}
- X
- X/*
- X * Decode a "percent" prototype character.
- X * A prototype string may include various "percent" escapes;
- X * that is, a percent sign followed by a single letter.
- X * Here we decode that letter and take the appropriate action,
- X * usually by appending something to the message being built.
- X */
- X static void
- Xprotochar(c, where)
- X int c;
- X int where;
- X{
- X POSITION pos;
- X POSITION len;
- X int n;
- X
- X switch (c)
- X {
- X case 'b': /* Current byte offset */
- X pos = curr_byte(where);
- X if (pos != NULL_POSITION)
- X ap_pos(pos);
- X else
- X ap_quest();
- X break;
- X case 'f': /* File name */
- X strtcpy(mp, current_file,
- X (unsigned int)(&message[sizeof(message)] - mp));
- X setmp();
- X break;
- X case 'i': /* Index into list of files */
- X ap_int(curr_ac + 1);
- X break;
- X case 'l': /* Current line number */
- X n = currline(where);
- X if (n != 0)
- X ap_int(n);
- X else
- X ap_quest();
- X break;
- X case 'm': /* Number of files */
- X ap_int(ac);
- X break;
- X case 'p': /* Percent into file */
- X pos = curr_byte(where);
- X len = ch_length();
- X if (pos != NULL_POSITION && len > 0)
- X ap_int((int)(100*pos / len));
- X else
- X ap_quest();
- X break;
- X case 's': /* Size of file */
- X len = ch_length();
- X if (len != NULL_POSITION)
- X ap_pos(len);
- X else
- X ap_quest();
- X break;
- X case 't': /* Truncate trailing spaces in the message */
- X while (mp > message && mp[-1] == ' ')
- X mp--;
- X break;
- X case 'x': /* Name of next file */
- X if (curr_ac + 1 < ac)
- X {
- X strtcpy(mp, av[curr_ac+1],
- X (unsigned int)(&message[sizeof(message)] - mp));
- X setmp();
- X } else
- X ap_quest();
- X break;
- X }
- X}
- X
- X/*
- X * Skip a false conditional.
- X * When a false condition is found (either a false IF or the ELSE part
- X * of a true IF), this routine scans the prototype string to decide
- X * where to resume parsing the string.
- X * We must keep track of nested IFs and skip them properly.
- X */
- X static char *
- Xskipcond(p)
- X register char *p;
- X{
- X register int iflevel = 1;
- X
- X for (;;) switch (*++p)
- X {
- X case '?':
- X /*
- X * Start of a nested IF.
- X */
- X iflevel++;
- X break;
- X case ':':
- X /*
- X * Else.
- X * If this matches the IF we came in here with,
- X * then we're done.
- X */
- X if (iflevel == 1)
- X return (p);
- X break;
- X case '.':
- X /*
- X * Endif.
- X * If this matches the IF we came in here with,
- X * then we're done.
- X */
- X if (--iflevel == 0)
- X return (p);
- X break;
- X case '\\':
- X /*
- X * Backslash escapes the next character.
- X */
- X ++p;
- X break;
- X case '\0':
- X /*
- X * Whoops. Hit end of string.
- X * This is a malformed conditional, but just treat it
- X * as if all active conditionals ends here.
- X */
- X return (p-1);
- X }
- X /*NOTREACHED*/
- X}
- X
- X static char *
- Xwherechar(p, wp)
- X char *p;
- X int *wp;
- X{
- X int c;
- X
- X switch (c = *p)
- X {
- X case 'b': case 'l': case 'p':
- X switch (*++p)
- X {
- X case 't': *wp = TOP; break;
- X case 'm': *wp = MIDDLE; break;
- X case 'b': *wp = BOTTOM; break;
- X case 'B': *wp = BOTTOM_PLUS_ONE; break;
- X default: *wp = TOP; break;
- X }
- X }
- X return (p);
- X}
- X
- X/*
- X * Construct a message based on a prototype string.
- X */
- X static char *
- Xpr_expand(proto, maxwidth)
- X char *proto;
- X int maxwidth;
- X{
- X register char *p;
- X register int c;
- X int where;
- X
- X mp = message;
- X
- X if (*proto == '\0')
- X return ("");
- X
- X for (p = proto; *p != '\0'; p++)
- X {
- X switch (*p)
- X {
- X default: /* Just put the character in the message */
- X *mp++ = *p;
- X break;
- X case '\\': /* Backslash escapes the next character */
- X p++;
- X *mp++ = *p;
- X break;
- X case '?': /* Conditional (IF) */
- X if ((c = *++p) == '\0')
- X --p;
- X else
- X {
- X p = wherechar(p, &where);
- X if (!cond(c, where))
- X p = skipcond(p);
- X }
- X break;
- X case ':': /* ELSE */
- X p = skipcond(p);
- X break;
- X case '.': /* ENDIF */
- X break;
- X case '%': /* Percent escape */
- X if ((c = *++p) == '\0')
- X --p;
- X else
- X {
- X p = wherechar(p, &where);
- X protochar(c, where);
- X }
- X break;
- X }
- X }
- X
- X new_file = 0;
- X if (mp == message)
- X return (NULL);
- X *mp = '\0';
- X if (maxwidth > 0 && mp >= message + maxwidth)
- X {
- X /*
- X * Message is too long.
- X * Return just the final portion of it.
- X */
- X return (mp - maxwidth);
- X }
- X return (message);
- X}
- X
- X/*
- X * Return a message suitable for printing by the "=" command.
- X */
- X public char *
- Xeq_message()
- X{
- X return (pr_expand(eqproto, 0));
- X}
- X
- X/*
- X * Return a prompt.
- X * This depends on the prompt type (SHORT, MEDIUM, LONG), etc.
- X * If we can't come up with an appropriate prompt, return NULL
- X * and the caller will prompt with a colon.
- X */
- X public char *
- Xpr_string()
- X{
- X return (pr_expand(prproto[pr_type], sc_width-so_width-se_width-2));
- X}
- END_OF_FILE
- echo shar: Extracting \"line.c\"
- sed "s/^X//" >'line.c' <<'END_OF_FILE'
- X/*
- X * Routines to manipulate the "line buffer".
- X * The line buffer holds a line of output as it is being built
- X * in preparation for output to the screen.
- X * We keep track of the PRINTABLE length of the line as it is being built.
- X */
- X
- X#include "less.h"
- X
- Xstatic char linebuf[1024]; /* Buffer which holds the current output line */
- Xstatic char *curr; /* Pointer into linebuf */
- Xstatic int column; /* Printable length, accounting for
- X backspaces, etc. */
- X/*
- X * A ridiculously complex state machine takes care of backspaces
- X * when in BS_SPECIAL mode. The complexity arises from the attempt
- X * to deal with all cases, especially involving long lines with underlining,
- X * boldfacing or whatever. There are still some cases which will break it.
- X *
- X * There are four states:
- X * LN_NORMAL is the normal state (not in underline mode).
- X * LN_UNDERLINE means we are in underline mode. We expect to get
- X * either a sequence like "_\bX" or "X\b_" to continue
- X * underline mode, or anything else to end underline mode.
- X * LN_BOLDFACE means we are in boldface mode. We expect to get sequences
- X * like "X\bX\b...X\bX" to continue boldface mode, or anything
- X * else to end boldface mode.
- X * LN_UL_X means we are one character after LN_UNDERLINE
- X * (we have gotten the '_' in "_\bX" or the 'X' in "X\b_").
- X * LN_UL_XB means we are one character after LN_UL_X
- X * (we have gotten the backspace in "_\bX" or "X\b_";
- X * we expect one more ordinary character,
- X * which will put us back in state LN_UNDERLINE).
- X * LN_BO_X means we are one character after LN_BOLDFACE
- X * (we have gotten the 'X' in "X\bX").
- X * LN_BO_XB means we are one character after LN_BO_X
- X * (we have gotten the backspace in "X\bX";
- X * we expect one more 'X' which will put us back
- X * in LN_BOLDFACE).
- X */
- Xstatic int ln_state; /* Currently in normal/underline/bold/etc mode? */
- X#define LN_NORMAL 0 /* Not in underline, boldface or whatever mode */
- X#define LN_UNDERLINE 1 /* In underline, need next char */
- X#define LN_UL_X 2 /* In underline, got char, need \b */
- X#define LN_UL_XB 3 /* In underline, got char & \b, need one more */
- X#define LN_BOLDFACE 4 /* In boldface, need next char */
- X#define LN_BO_X 5 /* In boldface, got char, need \b */
- X#define LN_BO_XB 6 /* In boldface, got char & \b, need same char */
- X
- Xpublic char *line; /* Pointer to the current line.
- X Usually points to linebuf. */
- X
- Xextern int bs_mode;
- Xextern int tabstop;
- Xextern int bo_width, be_width;
- Xextern int ul_width, ue_width;
- Xextern int sc_width, sc_height;
- X
- X/*
- X * Rewind the line buffer.
- X */
- X public void
- Xprewind()
- X{
- X line = curr = linebuf;
- X ln_state = LN_NORMAL;
- X column = 0;
- X}
- X
- X/*
- X * Append a character to the line buffer.
- X * Expand tabs into spaces, handle underlining, boldfacing, etc.
- X * Returns 0 if ok, 1 if couldn't fit in buffer.
- X */
- X
- X#define NEW_COLUMN(newcol) if ((newcol) + ((ln_state)?ue_width:0) > sc_width) \
- X return (1); else column = (newcol)
- X
- X public int
- Xpappend(c)
- X int c;
- X{
- X if (c == '\0')
- X {
- X /*
- X * Terminate any special modes, if necessary.
- X * Append a '\0' to the end of the line.
- X */
- X switch (ln_state)
- X {
- X case LN_UL_X:
- X curr[0] = curr[-1];
- X curr[-1] = UE_CHAR;
- X curr++;
- X break;
- X case LN_BO_X:
- X curr[0] = curr[-1];
- X curr[-1] = BE_CHAR;
- X curr++;
- X break;
- X case LN_UL_XB:
- X case LN_UNDERLINE:
- X *curr++ = UE_CHAR;
- X break;
- X case LN_BO_XB:
- X case LN_BOLDFACE:
- X *curr++ = BE_CHAR;
- X break;
- X }
- X ln_state = LN_NORMAL;
- X *curr = '\0';
- X return (0);
- X }
- X
- X if (curr > linebuf + sizeof(linebuf) - 12)
- X /*
- X * Almost out of room in the line buffer.
- X * Don't take any chances.
- X * {{ Linebuf is supposed to be big enough that this
- X * will never happen, but may need to be made
- X * bigger for wide screens or lots of backspaces. }}
- X */
- X return (1);
- X
- X if (bs_mode == BS_SPECIAL)
- X {
- X /*
- X * Advance the state machine.
- X */
- X switch (ln_state)
- X {
- X case LN_NORMAL:
- X if (curr <= linebuf + 1 || curr[-1] != '\b')
- X break;
- X
- X if (c == curr[-2])
- X goto enter_boldface;
- X if (c == '_' || curr[-2] == '_')
- X goto enter_underline;
- X curr -= 2;
- X break;
- X
- Xenter_boldface:
- X /*
- X * We have "X\bX" (including the current char).
- X * Switch into boldface mode.
- X */
- X if (column + bo_width + be_width + 1 >= sc_width)
- X /*
- X * Not enough room left on the screen to
- X * enter and exit boldface mode.
- X */
- X return (1);
- X
- X if (bo_width > 0 &&
- X curr > linebuf + 2 && curr[-3] == ' ')
- X {
- X /*
- X * Special case for magic cookie terminals:
- X * if the previous char was a space, replace
- X * it with the "enter boldface" sequence.
- X */
- X curr[-3] = BO_CHAR;
- X column += bo_width-1;
- X } else
- X {
- X curr[-1] = curr[-2];
- X curr[-2] = BO_CHAR;
- X column += bo_width;
- X curr++;
- X }
- X goto ln_bo_xb_case;
- X
- Xenter_underline:
- X /*
- X * We have either "_\bX" or "X\b_" (including
- X * the current char). Switch into underline mode.
- X */
- X if (column + ul_width + ue_width + 1 >= sc_width)
- X /*
- X * Not enough room left on the screen to
- X * enter and exit underline mode.
- X */
- X return (1);
- X
- X if (ul_width > 0 &&
- X curr > linebuf + 2 && curr[-3] == ' ')
- X {
- X /*
- X * Special case for magic cookie terminals:
- X * if the previous char was a space, replace
- X * it with the "enter underline" sequence.
- X */
- X curr[-3] = UL_CHAR;
- X column += ul_width-1;
- X } else
- X {
- X curr[-1] = curr[-2];
- X curr[-2] = UL_CHAR;
- X column += ul_width;
- X curr++;
- X }
- X goto ln_ul_xb_case;
- X /*NOTREACHED*/
- X case LN_UL_XB:
- X /*
- X * Termination of a sequence "_\bX" or "X\b_".
- X */
- X if (c != '_' && curr[-2] != '_' && c == curr[-2])
- X {
- X /*
- X * We seem to have run on from underlining
- X * into boldfacing - this is a nasty fix, but
- X * until this whole routine is rewritten as a
- X * real DFA, ... well ...
- X */
- X curr[0] = curr[-2];
- X curr[-2] = UE_CHAR;
- X curr[-1] = BO_CHAR;
- X curr += 2; /* char & non-existent backspace */
- X ln_state = LN_BO_XB;
- X goto ln_bo_xb_case;
- X }
- Xln_ul_xb_case:
- X if (c == '_')
- X c = curr[-2];
- X curr -= 2;
- X ln_state = LN_UNDERLINE;
- X break;
- X case LN_BO_XB:
- X /*
- X * Termination of a sequnce "X\bX".
- X */
- X if (c != curr[-2] && (c == '_' || curr[-2] == '_'))
- X {
- X /*
- X * We seem to have run on from
- X * boldfacing into underlining.
- X */
- X curr[0] = curr[-2];
- X curr[-2] = BE_CHAR;
- X curr[-1] = UL_CHAR;
- X curr += 2; /* char & non-existent backspace */
- X ln_state = LN_UL_XB;
- X goto ln_ul_xb_case;
- X }
- Xln_bo_xb_case:
- X curr -= 2;
- X ln_state = LN_BOLDFACE;
- X break;
- X case LN_UNDERLINE:
- X if (column + ue_width + bo_width + 1 + be_width >= sc_width)
- X /*
- X * We have just barely enough room to
- X * exit underline mode and handle a possible
- X * underline/boldface run on mixup.
- X */
- X return (1);
- X ln_state = LN_UL_X;
- X break;
- X case LN_BOLDFACE:
- X if (c == '\b')
- X {
- X ln_state = LN_BO_XB;
- X break;
- X }
- X if (column + be_width + ul_width + 1 + ue_width >= sc_width)
- X /*
- X * We have just barely enough room to
- X * exit underline mode and handle a possible
- X * underline/boldface run on mixup.
- X */
- X return (1);
- X ln_state = LN_BO_X;
- X break;
- X case LN_UL_X:
- X if (c == '\b')
- X ln_state = LN_UL_XB;
- X else
- X {
- X /*
- X * Exit underline mode.
- X * We have to shuffle the chars a bit
- X * to make this work.
- X */
- X curr[0] = curr[-1];
- X curr[-1] = UE_CHAR;
- X column += ue_width;
- X if (ue_width > 0 && curr[0] == ' ')
- X /*
- X * Another special case for magic
- X * cookie terminals: if the next
- X * char is a space, replace it
- X * with the "exit underline" sequence.
- X */
- X column--;
- X else
- X curr++;
- X ln_state = LN_NORMAL;
- X }
- X break;
- X case LN_BO_X:
- X if (c == '\b')
- X ln_state = LN_BO_XB;
- X else
- X {
- X /*
- X * Exit boldface mode.
- X * We have to shuffle the chars a bit
- X * to make this work.
- X */
- X curr[0] = curr[-1];
- X curr[-1] = BE_CHAR;
- X column += be_width;
- X if (be_width > 0 && curr[0] == ' ')
- X /*
- X * Another special case for magic
- X * cookie terminals: if the next
- X * char is a space, replace it
- X * with the "exit boldface" sequence.
- X */
- X column--;
- X else
- X curr++;
- X ln_state = LN_NORMAL;
- X }
- X break;
- X }
- X }
- X
- X if (c == '\t')
- X {
- X /*
- X * Expand a tab into spaces.
- X */
- X do
- X {
- X NEW_COLUMN(column+1);
- X } while ((column % tabstop) != 0);
- X *curr++ = '\t';
- X return (0);
- X }
- X
- X if (c == '\b')
- X {
- X if (bs_mode == BS_CONTROL)
- X {
- X /*
- X * Treat backspace as a control char: output "^H".
- X */
- X NEW_COLUMN(column+2);
- X *curr++ = ('H' | 0200);
- X } else
- X {
- X /*
- X * Output a real backspace.
- X */
- X column--;
- X *curr++ = '\b';
- X }
- X return (0);
- X }
- X
- X if (control_char(c))
- X {
- X /*
- X * Put a "^X" into the buffer.
- X * The 0200 bit is used to tell put_line() to prefix
- X * the char with a ^. We don't actually put the ^
- X * in the buffer because we sometimes need to move
- X * chars around, and such movement might separate
- X * the ^ from its following character.
- X * {{ This should be redone so that we can use an
- X * 8 bit (e.g. international) character set. }}
- X */
- X NEW_COLUMN(column+2);
- X *curr++ = (carat_char(c) | 0200);
- X return (0);
- X }
- X
- X /*
- X * Ordinary character. Just put it in the buffer.
- X */
- X NEW_COLUMN(column+1);
- X *curr++ = c;
- X return (0);
- X}
- X
- X/*
- X * Analogous to forw_line(), but deals with "raw lines":
- X * lines which are not split for screen width.
- X * {{ This is supposed to be more efficient than forw_line(). }}
- X */
- X public POSITION
- Xforw_raw_line(curr_pos)
- X POSITION curr_pos;
- X{
- X register char *p;
- X register int c;
- X POSITION new_pos;
- X
- X if (curr_pos == NULL_POSITION || ch_seek(curr_pos) ||
- X (c = ch_forw_get()) == EOI)
- X return (NULL_POSITION);
- X
- X p = linebuf;
- X
- X for (;;)
- X {
- X if (c == '\n' || c == EOI)
- X {
- X new_pos = ch_tell();
- X break;
- X }
- X if (p >= &linebuf[sizeof(linebuf)-1])
- X {
- X /*
- X * Overflowed the input buffer.
- X * Pretend the line ended here.
- X * {{ The line buffer is supposed to be big
- X * enough that this never happens. }}
- X */
- X new_pos = ch_tell() - 1;
- X break;
- X }
- X *p++ = c;
- X c = ch_forw_get();
- X }
- X *p = '\0';
- X line = linebuf;
- X return (new_pos);
- X}
- X
- X/*
- X * Analogous to back_line(), but deals with "raw lines".
- X * {{ This is supposed to be more efficient than back_line(). }}
- X */
- X public POSITION
- Xback_raw_line(curr_pos)
- X POSITION curr_pos;
- X{
- X register char *p;
- X register int c;
- X POSITION new_pos;
- X
- X if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 ||
- X ch_seek(curr_pos-1))
- X return (NULL_POSITION);
- X
- X p = &linebuf[sizeof(linebuf)];
- X *--p = '\0';
- X
- X for (;;)
- X {
- X c = ch_back_get();
- X if (c == '\n')
- X {
- X /*
- X * This is the newline ending the previous line.
- X * We have hit the beginning of the line.
- X */
- X new_pos = ch_tell() + 1;
- X break;
- X }
- X if (c == EOI)
- X {
- X /*
- X * We have hit the beginning of the file.
- X * This must be the first line in the file.
- X * This must, of course, be the beginning of the line.
- X */
- X new_pos = (POSITION)0;
- X break;
- X }
- X if (p <= linebuf)
- X {
- X /*
- X * Overflowed the input buffer.
- X * Pretend the line ended here.
- X */
- X new_pos = ch_tell() + 1;
- X break;
- X }
- X *--p = c;
- X }
- X line = p;
- X return (new_pos);
- X}
- END_OF_FILE
- echo shar: Extracting \"signal.c\"
- sed "s/^X//" >'signal.c' <<'END_OF_FILE'
- X/*
- X * Routines dealing with signals.
- X *
- X * A signal usually merely causes a bit to be set in the "signals" word.
- X * At some convenient time, the mainline code checks to see if any
- X * signals need processing by calling psignal().
- X * If we happen to be reading from a file [in iread()] at the time
- X * the signal is received, we call intread to interrupt the iread.
- X */
- X
- X#include "less.h"
- X#include <signal.h>
- X
- X/*
- X * "sigs" contains bits indicating signals which need to be processed.
- X */
- Xpublic int sigs;
- X
- X#define S_INTERRUPT 01
- X#ifdef SIGTSTP
- X#define S_STOP 02
- X#endif
- X#if defined(SIGWINCH) || defined(SIGWIND)
- X#define S_WINCH 04
- X#endif
- X
- Xextern int sc_width, sc_height;
- Xextern int screen_trashed;
- Xextern int lnloop;
- Xextern int linenums;
- Xextern int scroll;
- Xextern int reading;
- X
- X/*
- X * Interrupt signal handler.
- X */
- X static HANDLER
- Xinterrupt()
- X{
- X SIGNAL(SIGINT, interrupt);
- X sigs |= S_INTERRUPT;
- X if (reading)
- X intread();
- X}
- X
- X#ifdef SIGTSTP
- X/*
- X * "Stop" (^Z) signal handler.
- X */
- X static HANDLER
- Xstop()
- X{
- X SIGNAL(SIGTSTP, stop);
- X sigs |= S_STOP;
- X if (reading)
- X intread();
- X}
- X#endif
- X
- X#ifdef SIGWINCH
- X/*
- X * "Window" change handler
- X */
- X public HANDLER
- Xwinch()
- X{
- X SIGNAL(SIGWINCH, winch);
- X sigs |= S_WINCH;
- X if (reading)
- X intread();
- X}
- X#else
- X#ifdef SIGWIND
- X/*
- X * "Window" change handler
- X */
- X public HANDLER
- Xwinch()
- X{
- X SIGNAL(SIGWIND, winch);
- X sigs |= S_WINCH;
- X if (reading)
- X intread();
- X}
- X#endif
- X#endif
- X
- X/*
- X * Set up the signal handlers.
- X */
- X public void
- Xinit_signals(on)
- X int on;
- X{
- X if (on)
- X {
- X /*
- X * Set signal handlers.
- X */
- X (void) SIGNAL(SIGINT, interrupt);
- X#ifdef SIGTSTP
- X (void) SIGNAL(SIGTSTP, stop);
- X#endif
- X#ifdef SIGWINCH
- X (void) SIGNAL(SIGWINCH, winch);
- X#else
- X#ifdef SIGWIND
- X (void) SIGNAL(SIGWIND, winch);
- X#endif
- X#endif
- X } else
- X {
- X /*
- X * Restore signals to defaults.
- X */
- X (void) SIGNAL(SIGINT, SIG_DFL);
- X#ifdef SIGTSTP
- X (void) SIGNAL(SIGTSTP, SIG_DFL);
- X#endif
- X#ifdef SIGWINCH
- X (void) SIGNAL(SIGWINCH, SIG_IGN);
- X#endif
- X#ifdef SIGWIND
- X (void) SIGNAL(SIGWIND, SIG_IGN);
- X#endif
- X }
- X}
- X
- X/*
- X * Process any signals we have received.
- X * A received signal cause a bit to be set in "sigs".
- X */
- X public int
- Xpsignals()
- X{
- X register int tsignals;
- X
- X if ((tsignals = sigs) == 0)
- X return (0);
- X sigs = 0;
- X
- X#ifdef S_WINCH
- X if (tsignals & S_WINCH)
- X {
- X int old_width, old_height;
- X /*
- X * Re-execute get_term() to read the new window size.
- X */
- X old_width = sc_width;
- X old_height = sc_height;
- X get_term();
- X if (sc_width != old_width || sc_height != old_height)
- X {
- X scroll = (sc_height + 1) / 2;
- X screen_trashed = 1;
- X }
- X }
- X#endif
- X#ifdef SIGTSTP
- X if (tsignals & S_STOP)
- X {
- X /*
- X * Clean up the terminal.
- X */
- X#ifdef SIGTTOU
- X SIGNAL(SIGTTOU, SIG_IGN);
- X#endif
- X lower_left();
- X clear_eol();
- X deinit();
- X flush();
- X raw_mode(0);
- X#ifdef SIGTTOU
- X SIGNAL(SIGTTOU, SIG_DFL);
- X#endif
- X SIGNAL(SIGTSTP, SIG_DFL);
- X kill(getpid(), SIGTSTP);
- X /*
- X * ... Bye bye. ...
- X * Hopefully we'll be back later and resume here...
- X * Reset the terminal and arrange to repaint the
- X * screen when we get back to the main command loop.
- X */
- X SIGNAL(SIGTSTP, stop);
- X raw_mode(1);
- X init();
- X screen_trashed = 1;
- X }
- X#endif
- X if (tsignals & S_INTERRUPT)
- X {
- X bell();
- X /*
- X * {{ You may wish to replace the bell() with
- X * error("Interrupt"); }}
- X */
- X
- X /*
- X * If we were interrupted while in the "calculating
- X * line numbers" loop, turn off line numbers.
- X */
- X if (lnloop)
- X {
- X lnloop = 0;
- X linenums = 0;
- X error("Line numbers turned off");
- X }
- X
- X }
- X
- X return (1);
- X}
- END_OF_FILE
- echo shar: Extracting \"os.c\"
- sed "s/^X//" >'os.c' <<'END_OF_FILE'
- X/*
- X * Operating system dependent routines.
- X *
- X * Most of the stuff in here is based on Unix, but an attempt
- X * has been made to make things work on other operating systems.
- X * This will sometimes result in a loss of functionality, unless
- X * someone rewrites code specifically for the new operating system.
- X *
- X * The makefile provides defines to decide whether various
- X * Unix features are present.
- X */
- X
- X#include <stdio.h>
- X#include <signal.h>
- X#include <setjmp.h>
- X#include "less.h"
- X
- Xchar *getenv();
- X
- Xpublic int reading;
- X
- Xextern int screen_trashed;
- X
- Xstatic jmp_buf read_label;
- X
- X/*
- X * Pass the specified command to a shell to be executed.
- X * Like plain "system()", but handles resetting terminal modes, etc.
- X */
- X public void
- Xlsystem(cmd)
- X char *cmd;
- X{
- X int inp;
- X char cmdbuf[256];
- X char *shell;
- X
- X /*
- X * Print the command which is to be executed,
- X * unless the command starts with a "-".
- X */
- X if (cmd[0] == '-')
- X cmd++;
- X else
- X {
- X lower_left();
- X clear_eol();
- X putstr("!");
- X putstr(cmd);
- X putstr("\n");
- X }
- X
- X /*
- X * De-initialize the terminal and take out of raw mode.
- X */
- X deinit();
- X flush();
- X raw_mode(0);
- X
- X /*
- X * Restore signals to their defaults.
- X */
- X init_signals(0);
- X
- X /*
- X * Force standard input to be the terminal, "/dev/tty",
- X * even if less's standard input is coming from a pipe.
- X */
- X inp = dup(0);
- X close(0);
- X if (open("/dev/tty", 0) < 0)
- X dup(inp);
- X
- X /*
- X * Pass the command to the system to be executed.
- X * If we have a SHELL environment variable, use
- X * <$SHELL -c "command"> instead of just <command>.
- X * If the command is empty, just invoke a shell.
- X */
- X if ((shell = getenv("SHELL")) != NULL && *shell != '\0')
- X {
- X if (*cmd == '\0')
- X cmd = shell;
- X else
- X {
- X sprintf(cmdbuf, "%s -c \"%s\"", shell, cmd);
- X cmd = cmdbuf;
- X }
- X }
- X if (*cmd == '\0')
- X cmd = "sh";
- X
- X system(cmd);
- X
- X /*
- X * Restore standard input, reset signals, raw mode, etc.
- X */
- X close(0);
- X dup(inp);
- X close(inp);
- X
- X init_signals(1);
- X raw_mode(1);
- X init();
- X screen_trashed = 1;
- X#if defined(SIGWINCH) || defined(SIGWIND)
- X /*
- X * Since we were ignoring window change signals while we executed
- X * the system command, we must assume the window changed.
- X */
- X winch();
- X#endif
- X}
- X
- X/*
- X * Like read() system call, but is deliberately interruptable.
- X * A call to intread() from a signal handler will interrupt
- X * any pending iread().
- X */
- X public int
- Xiread(fd, buf, len)
- X int fd;
- X char *buf;
- X int len;
- X{
- X register int n;
- X
- X if (setjmp(read_label))
- X /*
- X * We jumped here from intread.
- X */
- X return (READ_INTR);
- X
- X flush();
- X reading = 1;
- X n = read(fd, buf, len);
- X reading = 0;
- X if (n < 0)
- X return (-1);
- X return (n);
- X}
- X
- X public void
- Xintread()
- X{
- X#if SIGSETMASK
- X sigsetmask(0);
- X#endif
- X longjmp(read_label, 1);
- X}
- X
- X#if GET_TIME
- X public long
- Xget_time()
- X{
- X long t;
- X
- X time(&t);
- X return (t);
- X}
- X#endif
- X
- X/*
- X * Expand a filename, substituting any environment variables, etc.
- X * The implementation of this is necessarily very operating system
- X * dependent. This implementation is unabashedly only for Unix systems.
- X */
- X#if GLOB
- X
- XFILE *popen();
- X
- X public char *
- Xglob(filename)
- X char *filename;
- X{
- X FILE *f;
- X char *p;
- X int ch;
- X char *cmd;
- X static char buffer[FILENAME];
- X
- X if (filename[0] == '#')
- X return (filename);
- X
- X /*
- X * We get the shell to expand the filename for us by passing
- X * an "echo" command to the shell and reading its output.
- X */
- X p = getenv("SHELL");
- X if (p == NULL || *p == '\0')
- X {
- X /*
- X * Read the output of <echo filename>.
- X */
- X cmd = calloc(strlen(filename)+8, sizeof(char));
- X if (cmd == NULL)
- X return (filename);
- X sprintf(cmd, "echo \"%s\"", filename);
- X } else
- X {
- X /*
- X * Read the output of <$SHELL -c "echo filename">.
- X */
- X cmd = calloc(strlen(p)+12);
- X if (cmd == NULL)
- X return (filename);
- X sprintf(cmd, "%s -c \"echo %s\"", p, filename);
- X }
- X
- X if ((f = popen(cmd, "r")) == NULL)
- X return (filename);
- X free(cmd);
- X
- X for (p = buffer; p < &buffer[sizeof(buffer)-1]; p++)
- X {
- X if ((ch = getc(f)) == '\n' || ch == EOF)
- X break;
- X *p = ch;
- X }
- X *p = '\0';
- X pclose(f);
- X return (buffer);
- X}
- X
- X#else
- X
- X public char *
- Xglob(filename)
- X char *filename;
- X{
- X return (filename);
- X}
- X
- X#endif
- X
- X
- X/*
- X * Returns NULL if the file can be opened and
- X * is an ordinary file, otherwise an error message
- X * (if it cannot be opened or is a directory, etc.)
- X */
- X
- X#if STAT
- X
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X
- X public char *
- Xbad_file(filename, message, len)
- X char *filename;
- X char *message;
- X unsigned int len;
- X{
- X struct stat statbuf;
- X
- X if (stat(filename, &statbuf) < 0)
- X return (errno_message(filename, message, len));
- X
- X if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
- X {
- X static char is_dir[] = " is a directory";
- X strtcpy(message, filename, len-sizeof(is_dir)-1);
- X strcat(message, is_dir);
- X return (message);
- X }
- X if ((statbuf.st_mode & S_IFMT) != S_IFREG)
- X {
- X static char not_reg[] = " is not a regular file";
- X strtcpy(message, filename, len-sizeof(not_reg)-1);
- X strcat(message, not_reg);
- X return (message);
- X }
- X return (NULL);
- X}
- X
- X#else
- X
- X public char *
- Xbad_file(filename, message, len)
- X char *filename;
- X char *message;
- X unsigned int len;
- X{
- X return (NULL);
- X}
- X
- X#endif
- X
- X/*
- X * errno_message: Return an error message based on the value of "errno".
- X * okreadfail: Return true if the previous failure of a read
- X * (on the input tty) should be considered ok.
- X */
- X
- X#if PERROR
- X
- Xextern char *sys_errlist[];
- Xextern int sys_nerr;
- Xextern int errno;
- X
- X public char *
- Xerrno_message(filename, message, len)
- X char *filename;
- X char *message;
- X unsigned int len;
- X{
- X char *p;
- X char msg[16];
- X
- X if (errno < sys_nerr)
- X p = sys_errlist[errno];
- X else
- X {
- X sprintf(msg, "Error %d", errno);
- X p = msg;
- X }
- X strtcpy(message, filename, len-strlen(p)-3);
- X strcat(message, ": ");
- X strcat(message, p);
- X return (message);
- X}
- X
- X#else
- X
- X public char *
- Xerrno_message(filename, message, len)
- X char *filename;
- X char *message;
- X unsigned int len;
- X{
- X static char msg[] = ": cannot open";
- X
- X strtcpy(message, filename, len-sizeof(msg)-1);
- X strcat(message, msg);
- X return (message);
- X}
- X
- X#endif
- END_OF_FILE
- echo shar: Extracting \"help.c\"
- sed "s/^X//" >'help.c' <<'END_OF_FILE'
- X#include "less.h"
- X
- X/*
- X * Display some help.
- X * Just invoke another "less" to display the help file.
- X *
- X * {{ This makes this function very simple, and makes changing the
- X * help file very easy, but it may present difficulties on
- X * (non-Unix) systems which do not supply the "system()" function. }}
- X */
- X
- X public void
- Xhelp()
- X{
- X char cmd[FILENAME+100];
- X
- X sprintf(cmd,
- X "-less -m '-PmHELP -- ?eEND -- Press g to see it again:Press RETURN for more., or q when done ' %s",
- X HELPFILE);
- X lsystem(cmd);
- X error("End of help");
- X}
- END_OF_FILE
- echo shar: Extracting \"ttyin.c\"
- sed "s/^X//" >'ttyin.c' <<'END_OF_FILE'
- X/*
- X * Routines dealing with getting input from the keyboard (i.e. from the user).
- X */
- X
- X#include "less.h"
- X
- Xstatic int tty;
- X
- X/*
- X * Open keyboard for input.
- X * (Just use file descriptor 2.)
- X */
- X public void
- Xopen_getchr()
- X{
- X tty = 2;
- X}
- X
- X/*
- X * Get a character from the keyboard.
- X */
- X public int
- Xgetchr()
- X{
- X char c;
- X int result;
- X
- X do
- X {
- X result = iread(tty, &c, 1);
- X if (result == READ_INTR)
- X return (READ_INTR);
- X if (result < 0)
- X {
- X /*
- X * Don't call error() here,
- X * because error calls getchr!
- X */
- X quit();
- X }
- X } while (result != 1);
- X return (c & 0177);
- X}
- END_OF_FILE
- echo shar: Extracting \"command.c\"
- sed "s/^X//" >'command.c' <<'END_OF_FILE'
- X/*
- X * User-level command processor.
- X */
- X
- X#include "less.h"
- X#include "position.h"
- X#include "cmd.h"
- X
- X#define NO_MCA 0
- X#define MCA_DONE 1
- X#define MCA_MORE 2
- X
- Xextern int erase_char, kill_char;
- Xextern int ispipe;
- Xextern int sigs;
- Xextern int quit_at_eof;
- Xextern int hit_eof;
- Xextern int sc_width;
- Xextern int sc_height;
- Xextern int sc_window;
- Xextern int curr_ac;
- Xextern int ac;
- Xextern int quitting;
- Xextern int scroll;
- Xextern char *first_cmd;
- Xextern char *every_first_cmd;
- Xextern char version[];
- Xextern char *current_file;
- X#if EDITOR
- Xextern char *editor;
- X#endif
- Xextern int screen_trashed; /* The screen has been overwritten */
- X
- Xstatic char cmdbuf[120]; /* Buffer for holding a multi-char command */
- X#if SHELL_ESCAPE
- Xstatic char *shellcmd = NULL; /* For holding last shell command for "!!" */
- X#endif
- Xstatic char *cp; /* Pointer into cmdbuf */
- Xstatic int cmd_col; /* Current column of the multi-char command */
- Xstatic int mca; /* The multicharacter command (action) */
- Xstatic int last_mca; /* The previous mca */
- Xstatic int number; /* The number typed by the user */
- Xstatic int wsearch; /* Search for matches (1) or non-matches (0) */
- X
- X/*
- X * Reset command buffer (to empty).
- X */
- Xcmd_reset()
- X{
- X cp = cmdbuf;
- X}
- X
- X/*
- X * Backspace in command buffer.
- X */
- X static int
- Xcmd_erase()
- X{
- X if (cp == cmdbuf)
- X /*
- X * Backspace past beginning of the string:
- X * this usually means abort the command.
- X */
- X return (1);
- X
- X if (control_char(*--cp))
- X {
- X /*
- X * Erase an extra character, for the carat.
- X */
- X backspace();
- X cmd_col--;
- X }
- X backspace();
- X cmd_col--;
- X return (0);
- X}
- X
- X/*
- X * Set up the display to start a new multi-character command.
- X */
- Xstart_mca(action, prompt)
- X int action;
- X char *prompt;
- X{
- X lower_left();
- X clear_eol();
- X putstr(prompt);
- X cmd_col = strlen(prompt);
- X mca = action;
- X}
- X
- X/*
- X * Process a single character of a multi-character command, such as
- X * a number, or the pattern of a search command.
- X */
- X static int
- Xcmd_char(c)
- X int c;
- X{
- X if (c == erase_char)
- X {
- X if (cmd_erase())
- X return (1);
- X } else if (c == kill_char)
- X {
- X /* {{ Could do this faster, but who cares? }} */
- X while (cmd_erase() == 0)
- X ;
- X } else if (cp >= &cmdbuf[sizeof(cmdbuf)-1])
- X {
- X /*
- X * No room in the command buffer.
- X */
- X bell();
- X } else if (cmd_col >= sc_width-3)
- X {
- X /*
- X * No room on the screen.
- X * {{ Could get fancy here; maybe shift the displayed
- X * line and make room for more chars, like ksh. }}
- X */
- X bell();
- X } else
- X {
- X /*
- X * Append the character to the string.
- X */
- X *cp++ = c;
- X if (control_char(c))
- X {
- X putchr('^');
- X cmd_col++;
- X c = carat_char(c);
- X }
- X putchr(c);
- X cmd_col++;
- X }
- X return (0);
- X}
- X
- X/*
- X * Return the number currently in the command buffer.
- X */
- X static int
- Xcmd_int()
- X{
- X *cp = '\0';
- X cp = cmdbuf;
- X return (atoi(cmdbuf));
- X}
- X
- X/*
- X * Move the cursor to lower left before executing a command.
- X * This looks nicer if the command takes a long time before
- X * updating the screen.
- X */
- X static void
- Xcmd_exec()
- X{
- X lower_left();
- X flush();
- X}
- X
- X/*
- X * Display the appropriate prompt.
- X */
- X static void
- Xprompt()
- X{
- X register char *p;
- X
- X if (first_cmd != NULL && *first_cmd != '\0')
- X {
- X /*
- X * No prompt necessary if commands are from first_cmd
- X * rather than from the user.
- X */
- X return;
- X }
- X
- X /*
- X * If nothing is displayed yet, display starting from line 1.
- X */
- X if (position(TOP) == NULL_POSITION)
- X jump_back(1);
- X else if (screen_trashed)
- X repaint();
- X
- X /*
- X * If the -E flag is set and we've hit EOF on the last file, quit.
- X */
- X if (quit_at_eof == 2 && hit_eof && curr_ac + 1 >= ac)
- X quit();
- X
- X /*
- X * Select the proper prompt and display it.
- X */
- X lower_left();
- X clear_eol();
- X p = pr_string();
- X if (p == NULL)
- X putchr(':');
- X else
- X {
- X so_enter();
- X putstr(p);
- X so_exit();
- X }
- X}
- X
- X/*
- X * Get command character.
- X * The character normally comes from the keyboard,
- X * but may come from the "first_cmd" string.
- X */
- X static int
- Xgetcc()
- X{
- X if (first_cmd == NULL)
- X return (getchr());
- X
- X if (*first_cmd == '\0')
- X {
- X /*
- X * Reached end of first_cmd input.
- X */
- X first_cmd = NULL;
- X if (cp > cmdbuf && position(TOP) == NULL_POSITION)
- X {
- X /*
- X * Command is incomplete, so try to complete it.
- X * There are only two cases:
- X * 1. We have "/string" but no newline. Add the \n.
- X * 2. We have a number but no command. Treat as #g.
- X * (This is all pretty hokey.)
- X */
- X if (mca != A_DIGIT)
- X /* Not a number; must be search string */
- X return ('\n');
- X else
- X /* A number; append a 'g' */
- X return ('g');
- X }
- X return (getchr());
- X }
- X return (*first_cmd++);
- X}
- X
- X/*
- X * Execute a multicharacter command.
- X */
- X static void
- Xexec_mca()
- X{
- X register char *p;
- X register int n;
- X
- X *cp = '\0';
- X cmd_exec();
- X switch (mca)
- X {
- X case A_F_SEARCH:
- X search(1, cmdbuf, number, wsearch);
- X break;
- X case A_B_SEARCH:
- X search(0, cmdbuf, number, wsearch);
- X break;
- X case A_FIRSTCMD:
- X /*
- X * Skip leading spaces or + signs in the string.
- X */
- X for (p = cmdbuf; *p == '+' || *p == ' '; p++)
- X ;
- X if (every_first_cmd != NULL)
- X free(every_first_cmd);
- X if (*p == '\0')
- X every_first_cmd = NULL;
- X else
- X every_first_cmd = save(p);
- X break;
- X case A_TOGGLE_OPTION:
- X toggle_option(cmdbuf, 1);
- X break;
- X case A_EXAMINE:
- X /*
- X * Ignore leading spaces in the filename.
- X */
- X for (p = cmdbuf; *p == ' '; p++)
- X ;
- X edit(glob(p));
- X break;
- X#if SHELL_ESCAPE
- X case A_SHELL:
- X /*
- X * !! just uses whatever is in shellcmd.
- X * Otherwise, copy cmdbuf to shellcmd,
- X * replacing any '%' with the current
- X * file name.
- X */
- X if (*cmdbuf != '!')
- X {
- X register char *fr, *to;
- X
- X /*
- X * Make one pass to see how big a buffer we
- X * need to allocate for the expanded shell cmd.
- X */
- X for (fr = cmdbuf; *fr != '\0'; fr++)
- X if (*fr == '%')
- X n += strlen(current_file);
- X else
- X n++;
- X
- X if (shellcmd != NULL)
- X free(shellcmd);
- X shellcmd = calloc(n+1, sizeof(char));
- X if (shellcmd == NULL)
- X {
- X error("cannot allocate memory");
- X break;
- X }
- X
- X /*
- X * Now copy the shell cmd, expanding any "%"
- X * into the current filename.
- X */
- X to = shellcmd;
- X for (fr = cmdbuf; *fr != '\0'; fr++)
- X {
- X if (*fr != '%')
- X *to++ = *fr;
- X else
- X {
- X strcpy(to, current_file);
- X to += strlen(to);
- X }
- X }
- X *to = '\0';
- X }
- X
- X if (shellcmd == NULL)
- X lsystem("");
- X else
- X lsystem(shellcmd);
- X error("!done");
- X break;
- X#endif
- X }
- X}
- X
- X/*
- X * Add a character to a multi-character command.
- X */
- X static int
- Xmca_char(c)
- X int c;
- X{
- X switch (mca)
- X {
- X case 0:
- X /*
- X * Not in a multicharacter command.
- X */
- X return (NO_MCA);
- X
- X case A_PREFIX:
- X /*
- X * In the prefix of a command.
- X */
- X return (NO_MCA);
- X
- X case A_DIGIT:
- X /*
- X * Entering digits of a number.
- X * Terminated by a non-digit.
- X */
- X if ((c < '0' || c > '9') &&
- X c != erase_char && c != kill_char)
- X {
- X /*
- X * Not part of the number.
- X * Treat as a normal command character.
- X */
- X number = cmd_int();
- X mca = 0;
- X return (NO_MCA);
- X }
- X break;
- X
- X case A_TOGGLE_OPTION:
- X /*
- X * Special case for the TOGGLE_OPTION command.
- X * if the option letter which was entered is a
- X * single-char option, execute the command immediately,
- X * so he doesn't have to hit RETURN.
- X */
- X if (cp == cmdbuf && c != erase_char && c != kill_char &&
- X single_char_option(c))
- X {
- X cmdbuf[0] = c;
- X cmdbuf[1] = '\0';
- X toggle_option(cmdbuf, 1);
- X return (MCA_DONE);
- X }
- X break;
- X }
- X
- X /*
- X * Any other multicharacter command
- X * is terminated by a newline.
- X */
- X if (c == '\n' || c == '\r')
- X {
- X /*
- X * Execute the command.
- X */
- X exec_mca();
- X return (MCA_DONE);
- X }
- X /*
- X * Append the char to the command buffer.
- X */
- X if (cmd_char(c))
- X /*
- X * Abort the multi-char command.
- X */
- X return (MCA_DONE);
- X /*
- X * Need another character.
- X */
- X return (MCA_MORE);
- X}
- X
- X/*
- X * Main command processor.
- X * Accept and execute commands until a quit command, then return.
- X */
- X public void
- Xcommands()
- X{
- X register int c;
- X register int action;
- X
- X last_mca = 0;
- X scroll = (sc_height + 1) / 2;
- X
- X for (;;)
- X {
- X mca = 0;
- X number = 0;
- X
- X /*
- X * See if any signals need processing.
- X */
- X if (sigs)
- X {
- X psignals();
- X if (quitting)
- X quit();
- X }
- X
- X /*
- X * Display prompt and accept a character.
- X */
- X cmd_reset();
- X prompt();
- X noprefix();
- X c = getcc();
- X
- X again:
- X if (sigs)
- X continue;
- X
- X /*
- X * If we are in a multicharacter command, call mca_char.
- X * Otherwise we call cmd_decode to determine the
- X * action to be performed.
- X */
- X if (mca)
- X switch (mca_char(c))
- X {
- X case MCA_MORE:
- X /*
- X * Need another character.
- X */
- X c = getcc();
- X goto again;
- X case MCA_DONE:
- X /*
- X * Command has been handled by mca_char.
- X * Start clean with a prompt.
- X */
- X continue;
- X case NO_MCA:
- X /*
- X * Not a multi-char command
- X * (at least, not anymore).
- X */
- X break;
- X }
- X
- X /*
- X * Decode the command character and decide what to do.
- X */
- X switch (action = cmd_decode(c))
- X {
- X case A_DIGIT:
- X /*
- X * First digit of a number.
- X */
- X start_mca(A_DIGIT, ":");
- X goto again;
- X
- X case A_F_SCREEN:
- X /*
- X * Forward one screen.
- X */
- X if (number <= 0)
- X number = sc_window;
- X if (number <= 0)
- X number = sc_height - 1;
- X cmd_exec();
- X forward(number, 1);
- X break;
- X
- X case A_B_SCREEN:
- X /*
- X * Backward one screen.
- X */
- X if (number <= 0)
- X number = sc_window;
- X if (number <= 0)
- X number = sc_height - 1;
- X cmd_exec();
- X backward(number, 1);
- X break;
- X
- X case A_F_LINE:
- X /*
- X * Forward N (default 1) line.
- X */
- X if (number <= 0)
- X number = 1;
- X cmd_exec();
- X forward(number, 0);
- X break;
- X
- X case A_B_LINE:
- X /*
- X * Backward N (default 1) line.
- X */
- X if (number <= 0)
- X number = 1;
- X cmd_exec();
- X backward(number, 0);
- X break;
- X
- X case A_F_SCROLL:
- X /*
- X * Forward N lines
- X * (default same as last 'd' or 'u' command).
- X */
- X if (number > 0)
- X scroll = number;
- X cmd_exec();
- X forward(scroll, 0);
- X break;
- X
- X case A_B_SCROLL:
- X /*
- X * Forward N lines
- X * (default same as last 'd' or 'u' command).
- X */
- X if (number > 0)
- X scroll = number;
- X cmd_exec();
- X backward(scroll, 0);
- X break;
- X
- X case A_FREPAINT:
- X /*
- X * Flush buffers, then repaint screen.
- X * Don't flush the buffers on a pipe!
- X */
- X if (!ispipe)
- X {
- X ch_init(0, 0);
- X clr_linenum();
- X }
- X /* FALLTHRU */
- X case A_REPAINT:
- X /*
- X * Repaint screen.
- X */
- X cmd_exec();
- X repaint();
- X break;
- X
- X case A_GOLINE:
- X /*
- X * Go to line N, default beginning of file.
- X */
- X if (number <= 0)
- X number = 1;
- X cmd_exec();
- X jump_back(number);
- X break;
- X
- X case A_PERCENT:
- X /*
- X * Go to a specified percentage into the file.
- X */
- X if (number < 0)
- X number = 0;
- X if (number > 100)
- X number = 100;
- X cmd_exec();
- X jump_percent(number);
- X break;
- X
- X case A_GOEND:
- X /*
- X * Go to line N, default end of file.
- X */
- X cmd_exec();
- X if (number <= 0)
- X jump_forw();
- X else
- X jump_back(number);
- X break;
- X
- X case A_STAT:
- X /*
- X * Print file name, etc.
- X */
- X cmd_exec();
- X error(eq_message());
- X break;
- X
- X case A_VERSION:
- X /*
- X * Print version number, without the "@(#)".
- X */
- X cmd_exec();
- X error(version+4);
- X break;
- X
- X case A_QUIT:
- X /*
- X * Exit.
- X */
- X quit();
- X
- X case A_F_SEARCH:
- X case A_B_SEARCH:
- X /*
- X * Search for a pattern.
- X * Accept chars of the pattern until \n.
- X */
- X if (number <= 0)
- X number = 1;
- X start_mca(action, (action==A_F_SEARCH) ? "/" : "?");
- X last_mca = mca;
- X wsearch = 1;
- X c = getcc();
- X if (c == '!')
- X {
- X /*
- X * Invert the sense of the search.
- X * Set wsearch to 0 and get a new
- X * character for the start of the pattern.
- X */
- X start_mca(action,
- X (action==A_F_SEARCH) ? "!/" : "!?");
- X wsearch = 0;
- X c = getcc();
- X }
- X goto again;
- X
- X case A_AGAIN_SEARCH:
- X /*
- X * Repeat previous search.
- X */
- X if (number <= 0)
- X number = 1;
- X if (wsearch)
- X start_mca(last_mca,
- X (last_mca==A_F_SEARCH) ? "/" : "?");
- X else
- X start_mca(last_mca,
- X (last_mca==A_F_SEARCH) ? "!/" : "!?");
- X cmd_exec();
- X search(mca==A_F_SEARCH, (char *)NULL, number, wsearch);
- X break;
- X
- X case A_HELP:
- X /*
- X * Help.
- X */
- X lower_left();
- X clear_eol();
- X putstr("help");
- X cmd_exec();
- X help();
- X break;
- X
- X case A_EXAMINE:
- X /*
- X * Edit a new file. Get the filename.
- X */
- X cmd_reset();
- X start_mca(A_EXAMINE, "Examine: ");
- X c = getcc();
- X goto again;
- X
- X case A_VISUAL:
- X /*
- X * Invoke an editor on the input file.
- X */
- X#if EDITOR
- X if (ispipe)
- X {
- X error("Cannot edit standard input");
- X break;
- X }
- X /*
- X * Try to pass the line number to the editor.
- X */
- X cmd_exec();
- X c = currline(MIDDLE);
- X if (c == 0)
- X sprintf(cmdbuf, "%s %s",
- X editor, current_file);
- X else
- X sprintf(cmdbuf, "%s +%d %s",
- X editor, c, current_file);
- X lsystem(cmdbuf);
- X ch_init(0, 0);
- X clr_linenum();
- X break;
- X#else
- X error("Command not available");
- X break;
- X#endif
- X
- X case A_NEXT_FILE:
- X /*
- X * Examine next file.
- X */
- X if (number <= 0)
- X number = 1;
- X next_file(number);
- X break;
- X
- X case A_PREV_FILE:
- X /*
- X * Examine previous file.
- X */
- X if (number <= 0)
- X number = 1;
- X prev_file(number);
- X break;
- X
- X case A_TOGGLE_OPTION:
- X /*
- X * Toggle a flag setting.
- X */
- X cmd_reset();
- X start_mca(A_TOGGLE_OPTION, "-");
- X c = getcc();
- X goto again;
- X
- X case A_DISP_OPTION:
- X /*
- X * Report a flag setting.
- X */
- X cmd_reset();
- X start_mca(A_DISP_OPTION, "_");
- X c = getcc();
- X if (c == erase_char || c == kill_char)
- X break;
- X cmdbuf[0] = c;
- X cmdbuf[1] = '\0';
- X toggle_option(cmdbuf, 0);
- X break;
- X
- X case A_FIRSTCMD:
- X /*
- X * Set an initial command for new files.
- X */
- X cmd_reset();
- X start_mca(A_FIRSTCMD, "+");
- X c = getcc();
- X goto again;
- X
- X case A_SHELL:
- X /*
- X * Shell escape.
- X */
- X#if SHELL_ESCAPE
- X cmd_reset();
- X start_mca(A_SHELL, "!");
- X c = getcc();
- X goto again;
- X#else
- X error("Command not available");
- X break;
- X#endif
- X
- X case A_SETMARK:
- X /*
- X * Set a mark.
- X */
- X lower_left();
- X clear_eol();
- X start_mca(A_SETMARK, "mark: ");
- X c = getcc();
- X if (c == erase_char || c == kill_char)
- X break;
- X setmark(c);
- X break;
- X
- X case A_GOMARK:
- X /*
- X * Go to a mark.
- X */
- X lower_left();
- X clear_eol();
- X start_mca(A_GOMARK, "goto mark: ");
- X c = getcc();
- X if (c == erase_char || c == kill_char)
- X break;
- X gomark(c);
- X break;
- X
- X case A_PREFIX:
- X /*
- X * The command is incomplete (more chars are needed).
- X * Display the current char so the user knows
- X * what's going on and get another character.
- X */
- X if (mca != A_PREFIX)
- X start_mca(A_PREFIX, "& ");
- X if (control_char(c))
- X {
- X putchr('^');
- X c = carat_char(c);
- X }
- X putchr(c);
- X c = getcc();
- X goto again;
- X
- X default:
- X bell();
- X break;
- X }
- X }
- X}
- END_OF_FILE
-
-
-